home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / NCSA⁄BYU TCP⁄IP / tcp.c < prev    next >
Text File  |  1991-06-27  |  18KB  |  667 lines

  1. /*
  2. *   TCP routines
  3. *
  4. ****************************************************************************
  5. *                                                                          *
  6. *      part of:                                                            *
  7. *      TCP/UDP/ICMP/IP Network kernel for NCSA Telnet                      *
  8. *      by Tim Krauskopf                                                    *
  9. *                                                                          *
  10. *      National Center for Supercomputing Applications                     *
  11. *      152 Computing Applications Building                                 *
  12. *      605 E. Springfield Ave.                                             *
  13. *      Champaign, IL  61820                                                *
  14. *                                                                          *
  15. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  16. *                                                                          *
  17. ****************************************************************************
  18. *   Tim Krauskopf       Fall 1986
  19. */
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. #include <Events.h>
  24.  
  25. #include "protocol.h"
  26. #include "data.h"
  27. #include "tools.h"
  28. #include "mactools.h"
  29.  
  30. extern uint16 ipcheck
  31.   (
  32.     void *buf,
  33.     int wdcnt
  34.   );
  35.  
  36. extern uint16 tcpcheck
  37.   (
  38.     void *phd,
  39.     void *buf,
  40.     int btcnt
  41.   );
  42.  
  43. static int pnum;
  44.  
  45. /***************************************************************************/
  46. /*  tcpsend
  47. *     transmits a TCP packet.  
  48. *
  49. *   For IP:
  50. *      sets ident,check,totallen
  51. *   For TCP:
  52. *      sets seq and window from port information,
  53. *        fills in the pseudo header and computes the checksum.
  54. *      Assumes that all fields not filled in here are filled in by the
  55. *      calling proc or were filled in by makeport(). 
  56. *      (see all inits in protinit)
  57. *
  58. */
  59. int tcpsend
  60.   (
  61.     struct port *pport,
  62.     int dlen
  63.   )
  64.     {
  65.     struct port *p;
  66.  
  67.     p = pport;
  68.  
  69.     if (p == NULL) {
  70.         netposterr(404);
  71.         return(-1);
  72.     }
  73.  
  74. /*
  75. *  do IP header first
  76. */
  77.     p->tcpout.i.ident = intswap(nnipident++);
  78.     p->tcpout.i.tlen = intswap(sizeof(struct iph)+sizeof(struct tcph) + dlen);
  79.     p->tcpout.i.check = 0;                /* install checksum */
  80.     p->tcpout.i.check = ipcheck(&p->tcpout.i,10);
  81. /*
  82. *  do TCP header
  83. */
  84.     p->tcpout.t.seq = longswap(p->out.nxt);            /* bytes swapped */
  85.  
  86. /*
  87. *  if the port has some credit limit, use it instead of large
  88. *  window buffer.  Generally demanded by hardware limitations.
  89. */
  90.     if (p->credit < p->in.size)
  91.         p->tcpout.t.window = intswap(p->credit);
  92.     else
  93.         p->tcpout.t.window = intswap(p->in.size);    /* window size */
  94.  
  95. /*
  96. *  prepare pseudo-header for checksum
  97. */
  98.     p->tcps.tcplen = intswap(dlen+sizeof(TCPLAYER));
  99.     p->tcpout.t.check = 0;
  100.     p->tcpout.t.check = tcpcheck(&p->tcps,&p->tcpout.t,dlen+sizeof(struct tcph));
  101.  
  102.     p->out.lasttime = time(NULL);
  103.  
  104.     return(dlayersend(&p->tcpout,
  105.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(TCPLAYER)+dlen));
  106.  
  107. } /* tcpsend */
  108.  
  109. /**********************************************************************/
  110. /*  checkmss
  111. *  Look at incoming SYN,ACK packet and check for the options field
  112. *  containing a TCP Maximum segment size option.  If it has one,
  113. *  then set the port's internal value to make sure that it never
  114. *  exceeds that segment size.
  115. */
  116. void checkmss
  117.   (
  118.     struct port *prt,
  119.     TCPKT *p,
  120.     int hlen
  121.   )
  122.     {
  123.     unsigned int i;
  124. /*
  125. *  check header for maximum segment size option
  126. */
  127.     if (hlen > 20 && p->x.options[0] == 2 && p->x.options[1] == 4) {
  128.         movebytes(&i,&p->x.options[2],2);    /* swapped value of maxseg */
  129.         i = intswap(i);
  130.         if (i < prt->sendsize)                /* we have our own limits too */
  131.             prt->sendsize = i;
  132.     }
  133. } /* checkmss */
  134.  
  135. /***************************************************************************/
  136. /*  ackcheck
  137. *   take an incoming packet and see if there is an ACK for the outgoing
  138. *   side.  Use that ACK to dequeue outgoing data.
  139. */
  140. int ackcheck
  141.   (
  142.     struct port *p,
  143.     TCPKT *t,
  144.     int pnum
  145.   )
  146.     {
  147.     uint32 ak;
  148.     int32 rttl;
  149.     int i;
  150.  
  151.     if ((t->t.flags & TRESET) && (t->t.seq == p->tcpout.t.ack)) {
  152.         netposterr(405);
  153.         p->state = SCLOSED;
  154.         netputuev(CONCLASS,CONCLOSE,pnum);
  155.         return(1);
  156.     }
  157.  
  158.     if (!(t->t.flags & TACK))                /* check ACK flag */
  159.         return(1);                             /* if no ACK, no go */
  160.  
  161.     p->out.size = intswap(t->t.window);    /* allowable transmission size */
  162.  
  163. /*
  164. *  rmqueue any bytes which have been ACKed, update p->out.nxt to the
  165. *  new next seq number for outgoing.  Update send window.
  166. *
  167. */
  168.     ak = longswap(t->t.ack);            /* other side's ACK */
  169. /*
  170. *  Need to add code to check for wrap-around of sequence space
  171. *  for ak.  ak - p->out.ack may be affected by sequence wraparound.
  172. *  If you have good, efficient code for this, please send it to me.
  173. *
  174. *  If ak is not increasing (above p->out.nxt) then we should assume
  175. *  that it is a duplicate packet or one of those stupid keepalive
  176. *  packets that 4.2 sends out.
  177. */
  178.     if (ak > p->out.nxt) {
  179.         rmqueue(&p->out,(int)(ak - p->out.ack));    /* take off of queue */
  180.         p->out.nxt = ak;
  181.         p->out.ack = ak;
  182. /*
  183. *  Check to see if this acked our most recent transmission.  If so, adjust
  184. *  the RTO value to reflect the newly measured RTT.  This formula reduces
  185. *  the RTO value so that it gradually approaches the most recent round
  186. *  trip measurement.  When a packet is retransmitted, this value is
  187. *  doubled (exponential backoff).
  188. */
  189.         rttl = time(NULL) - p->out.lasttime;
  190.         if (!p->out.contain &&             /* just now emptied queue */
  191.             rttl < (long)(MAXRTO) && p->rto >= MINRTO) {
  192.             i = (int)(rttl);
  193.             i = ((p->rto-MINRTO)*3 + i + 1) >> 2;    /* smoothing function */
  194.             p->rto = i+MINRTO;
  195.         }
  196.  
  197.         if (p->out.size > 0)
  198.             p->out.lasttime = 0L;            /* forces xmit */
  199.         return(0);
  200.     }
  201.     return(1);
  202. } /* ackcheck */
  203.  
  204. /***************************************************************************/
  205. /* checkfin
  206. *   Check the FIN bit of an incoming packet to see if the connection
  207. *   should be closing, ACK it if we need to.
  208. *   Half open connections immediately, automatically close.  We do
  209. *   not support them.  As soon as the incoming data is delivered, the
  210. *   connection will close.
  211. */
  212. void checkfin
  213.   (
  214.     struct port *prt,
  215.     TCPKT *pkt
  216.   )
  217.     {
  218.  
  219.     if (pkt->t.flags & TFIN) {        /* fin bit found */
  220.  
  221.         prt->in.nxt++;                /* count the FIN byte */
  222.         prt->state = SCWAIT;        /* close-wait */
  223.         prt->tcpout.t.ack = longswap(prt->in.nxt);    /* set ACK in packet */
  224.         prt->credit = 0;
  225.         prt->out.lasttime = 0L;        /* cause ACK to be sent */
  226.         netputuev(CONCLASS,CONCLOSE,pnum);
  227.  
  228. /*
  229. *   At this point, we know that we have received all data that the other
  230. *   side is allowed to send.  Some of that data may still be in the 
  231. *   incoming queue.  As soon as that queue empties, finish off the TCP
  232. *   close sequence.  We are not allowing the user to utilize a half-open
  233. *   connection, but we cannot close before the user has received all of
  234. *   the data from the incoming queue.
  235. */
  236.         if (!prt->in.contain) {                    /* data remaining? */
  237.             prt->tcpout.t.flags = TFIN | TACK;
  238.             tcpsend(prt,0);
  239.             prt->state = SLAST;
  240.         }
  241.     }
  242. } /* checkfin */
  243.  
  244. /***************************************************************************/
  245. /*  estab1986
  246. *   take a packet which has arrived for an established connection and
  247. *   put it where it belongs.
  248. */
  249. int estab1986
  250.   (
  251.     struct port *prt,
  252.     TCPKT *pkt,
  253.     int tlen,
  254.     int hlen
  255.   )
  256.     {
  257.     int dlen;
  258.     uint32 sq,want;
  259.  
  260.     dlen = tlen-hlen;
  261.     
  262. #ifdef OLDM
  263. /*  problem with old way is that dlen==0 is not checked to see if it is in
  264.   seq window */
  265.   
  266.     if (dlen <= 0) {                        /* only an ACK packet */
  267.         checkfin(prt,pkt);                    /* might still have FIN */
  268.         return(0);
  269.     }
  270. #endif
  271.  
  272. /*
  273. *  see if we want this packet, or is it a duplicate?
  274. */
  275.     sq = longswap(pkt->t.seq);
  276.     want = prt->in.nxt;
  277.  
  278.     if (sq != want) {                            /* we may want it, may not */
  279.  
  280.         if (sq < want && sq+dlen >= want) {      /* overlap */
  281.             hlen += want-sq;                    /* offset desired */
  282.             dlen -= want-sq;                    /* skip this much */
  283.         }
  284.         else {                                    /* tough it */
  285.             prt->out.lasttime = 0L;                /* make the ACK time out */
  286.             return(-1);
  287.         }
  288.     }
  289.     else if (dlen <= 0) {                        /* only an ACK packet */
  290.         checkfin(prt,pkt);                        /* might still have FIN */
  291.         return(0);
  292.     }
  293.  
  294. /*
  295. *  If we have room in the window, update the ACK field values
  296. */
  297.     if (prt->in.size >= dlen) {
  298.         prt->in.nxt += dlen;                /* new ack value */
  299.         prt->tcpout.t.ack = longswap(prt->in.nxt);
  300.         prt->in.size -= dlen;                /* new window size */
  301.  
  302.         prt->out.lasttime = 0L;                /* force timeout for ACK */
  303.  
  304.         enqueue(&prt->in,pkt->x.data+hlen-20,dlen);
  305.         netputuev(CONCLASS,CONDATA,pnum);    /* tell user about it */
  306.  
  307.         prt->in.lasttime = time(NULL);
  308.  
  309.     }
  310.  
  311.     else {                                    /* no room in input buffer */
  312.         prt->out.lasttime = 0L;                /* re-ack old sequence value */
  313.  
  314.     }
  315.  
  316. /* 
  317. *  Check the FIN bit to see if this connection is closing
  318. */
  319.     checkfin(prt,pkt);
  320.  
  321.     return(0);
  322. } /* estab1986 */
  323.  
  324. /**********************************************************************/
  325. /*  tcpdo
  326. *  Looking at the port structure for the destination port, deliver
  327. *  the incoming packet.
  328. */
  329. int tcpdo
  330.   (
  331.     struct port *prt,
  332.     TCPKT *p,
  333.     int tlen,
  334.     int hlen
  335.   )
  336.     {
  337.  
  338.     switch (prt->state) {
  339.  
  340.         case SLISTEN:                    /* waiting for remote connection */
  341.             if (p->t.flags & TSYN) {    /* receive SYN */
  342. /*
  343. *   remember anything important from the incoming TCP header 
  344. */
  345.                 prt->out.size = intswap(p->t.window);    /* credit window */
  346.                 prt->out.port = intswap(p->t.source);
  347.                 prt->in.nxt = longswap(p->t.seq) + 1;
  348. /*
  349. *  set the necessary fields in the outgoing TCP packet
  350. */
  351.                 prt->tcpout.t.dest = p->t.source;
  352.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  353.                 prt->tcpout.t.flags = TSYN | TACK;
  354.                 prt->tcpout.t.hlen = 24 << 2;
  355. /*
  356. *  note that the maxmimum segment size is installed by 'netlisten()'
  357. *  hence the header length is 24, not 20
  358. */
  359.                                 
  360. /*
  361. *  initialize all of the low-level transmission stuff (IP and lower)
  362. */
  363.                 movebytes(prt->tcps.dest,p->i.ipsource,4);
  364.                 movebytes(prt->tcpout.i.ipdest,p->i.ipsource,4);
  365.                 movebytes(prt->tcpout.d.dest,p->d.me,DADDLEN);
  366. #ifdef MAC
  367. /*
  368. *   look up address in the arp cache if using Atalk encapsulation
  369. */
  370.     if (!nnemac) {
  371.         unsigned char *pc;
  372.             pc = getdlayer(p->i.ipsource);
  373.             if (pc != NULL)
  374.                 movebytes(prt->tcpout.d.dest,pc,DADDLEN);
  375.             else
  376.                 return(0);        /* no hope this time */
  377.     }
  378. #endif
  379.  
  380.                 tcpsend(prt,4);
  381.                 prt->state = SSYNR;        /* syn received */
  382.             }
  383.             break;
  384.         case SSYNR:
  385.             if (!(p->t.flags & TACK)) {
  386.                 tcpsend(prt,4);
  387.                 break;                    /* not the right one */
  388.             }
  389.             prt->tcpout.t.hlen = 20 << 2;
  390.             prt->out.lasttime = time(NULL);            /* don't need response */
  391.             prt->out.nxt++;                            /* count SYN as sent */
  392.             prt->out.ack = longswap(p->t.ack);         /* starting ACK value */
  393.             prt->out.size = intswap(p->t.window);    /* allowed window */
  394.             prt->tcpout.t.flags = TACK;        /* starting ACK flag */
  395.             prt->state = SEST;                /* drop through to established */
  396.             netputevent(CONCLASS,CONOPEN,pnum);
  397.             checkmss(prt,p,hlen);            /* see if MSS option is there */
  398.  
  399.                                             /* fall through */
  400.         case SEST:
  401.             /* normal data transmission */
  402.             /*
  403.             *  check and accept a possible piggybacked ack
  404.             */
  405.             ackcheck(prt,p,pnum);
  406.  
  407.             estab1986(prt,p,tlen,hlen);
  408.             return(0);
  409.         case SSYNS:                /* check to see if it ACKS correctly */
  410.                                 /* remember that tcpout is pre-set-up */
  411.             if (p->t.flags & TACK) {        /* It is ACKING us */
  412.                 if (longswap(p->t.ack) != prt->out.nxt) {
  413.                     netposterr(401);
  414.                     return(1);
  415.                 }
  416.             }
  417.             if (p->t.flags & TRESET) {
  418.                 netposterr(507);
  419.                 prt->state = SCLOSED;
  420.                 netputuev(CONCLASS,CONCLOSE,pnum);
  421.                 return(1);
  422.             }
  423.             if (p->t.flags & TSYN) {            /* need to send ACK */
  424.                 prt->tcpout.t.flags = TACK;
  425.                 prt->in.nxt = longswap(p->t.seq) + 1;
  426.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  427.                 prt->out.ack = longswap(p->t.ack);
  428.                 prt->out.size = intswap(p->t.window);    /* credit window */
  429.                 prt->out.lasttime = 0L;
  430.                 if (p->t.flags & TACK) {
  431.                     prt->state = SEST;
  432.                     netputevent(CONCLASS,CONOPEN,pnum);
  433.                     checkmss(prt,p,hlen);
  434.                 }
  435.                 else
  436.                     prt->state = SSYNR;        /* syn received */
  437.             }
  438.             break;
  439.         case SCWAIT:
  440.             ackcheck(prt,p,pnum);
  441.             if (!prt->in.contain) {
  442.                 prt->tcpout.t.flags = TFIN | TACK;
  443.                 prt->out.lasttime = 0L;
  444.                 prt->state = SLAST;
  445.             }
  446.             break;
  447.         case SLAST:
  448.             /* check ack of FIN, or reset to see if we are done */
  449.             if ((p->t.flags & TRESET) || (longswap(p->t.ack) == prt->out.nxt+1))
  450.                 prt->state = SCLOSED;
  451.             break;
  452.         case SFW1:                            /* waiting for ACK of FIN */
  453.                                             /* throw away data */
  454.             prt->in.nxt = longswap(p->t.seq)+tlen-hlen;
  455.             if (p->t.flags & TRESET)
  456.                 prt->state = SCLOSED;
  457.             else if (longswap(p->t.ack) != prt->out.nxt+1) {
  458.                 if (p->t.flags & TFIN) {    /* got FIN, no ACK for mine */
  459.                     prt->in.nxt++;                /* account for FIN byte */
  460.                     prt->tcpout.t.ack = longswap(prt->in.nxt);
  461.                     prt->tcpout.t.flags = TACK;    /* final byte has no FIN flag */
  462.                     prt->out.lasttime = 0L;        /* cause last ACK to be sent */
  463.                     prt->state = SCLOSING;
  464.                 }
  465.                 else {
  466.                     prt->tcpout.t.ack = longswap(prt->in.nxt);
  467.                     prt->tcpout.t.flags = TACK | TFIN;
  468.                     prt->out.lasttime = 0L;
  469.                 }
  470.             }
  471.             else if (p->t.flags & TFIN) {    /* ACK and FIN */
  472.                 prt->in.nxt++;                /* account for his FIN flag */
  473.                 prt->out.nxt++;                /* account for my FIN */
  474.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  475.                 prt->tcpout.t.flags = TACK;    /* final byte has no FIN flag */
  476.                 prt->out.lasttime = 0L;        /* cause last ACK to be sent */
  477.                 prt->state = STWAIT;        /* we are done */
  478.             }
  479.             else {                            /* got ACK, no FIN */
  480.                 prt->out.nxt++;                /* account for my FIN byte */
  481.                 prt->tcpout.t.flags = TACK;    /* final pkt has no FIN flag */
  482.                 prt->state = SFW2;
  483.             }
  484.             break;
  485.         case SFW2:                                /* want FIN */
  486.             prt->in.nxt = longswap(p->t.seq)+tlen-hlen;
  487.             if (p->t.flags & TRESET)
  488.                 prt->state = SCLOSED;
  489.             else if (p->t.flags & TFIN) {        /* we got FIN */
  490.                 prt->in.nxt++;                    /* count his FIN byte */
  491.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  492.                 prt->out.lasttime = 0L;        /* cause last ACK to be sent */
  493.                 prt->state = STWAIT;
  494.             }
  495.             break;
  496.         case SCLOSING:                        /* want ACK of FIN */
  497.             if (p->t.flags & TRESET)
  498.                 prt->state = SCLOSED;
  499.             else if (!ackcheck(prt,p,pnum)) {
  500.                 prt->out.nxt++;                /* account for my FIN byte */
  501.                 prt->state = STWAIT;        /* time-wait state next */
  502.             }
  503.             break;
  504.         case STWAIT:                        /* ack FIN again? */
  505.             if (p->t.flags & TRESET)
  506.                 prt->state = SCLOSED;
  507.             if (p->t.flags & TFIN)             /* only if he wants it */
  508.                 prt->out.lasttime = 0L;
  509.             if (prt->out.lasttime && 
  510.                 (prt->out.lasttime + WAITTIME < time(NULL))) 
  511.                 prt->state = SCLOSED;
  512.             break;            
  513.         case SCLOSED:
  514.             prt->in.port = prt->out.port = 0;
  515.             break;
  516.         default:
  517.             netposterr(403);            /* unknown tcp state */
  518.             break;
  519.     }
  520.     return(0);
  521. } /* tcpdo */
  522.  
  523. /**********************************************************************/
  524. /* tcpreset
  525. *  Send a reset packet back to sender
  526. *  Use the packet which just came in as a template to return to
  527. *  sender.  Fill in all of the fields necessary and dlayersend it back.
  528. */
  529. int tcpreset
  530.   (
  531.     TCPKT *t
  532.   )
  533.     {
  534.     uint tport;
  535.     struct pseudotcp xxx;
  536.  
  537.     if (t->t.flags & TRESET)        /* don't reset a reset */
  538.         return(1);
  539.  
  540. /*
  541. *  swap TCP layer portions for sending back
  542. */
  543.     if (t->t.flags & TACK) {
  544.         t->t.seq = t->t.ack;        /* ack becomes next seq # */
  545.         t->t.ack = 0L;                /* ack # is 0 */
  546.     }
  547.     else {
  548.         t->t.ack = longswap(longswap(t->t.seq)+t->i.tlen-sizeof(IPLAYER));
  549.         t->t.seq = 0L;
  550.     }
  551.  
  552.     t->t.flags = TRESET;
  553.     tport = t->t.source;                    /* swap port #'s */
  554.     t->t.source = t->t.dest;
  555.     t->t.dest = tport;
  556.     t->t.hlen = 20 << 2;                    /* header len */
  557.     t->t.window = 0;
  558.  
  559. /*
  560. *  create pseudo header for checksum
  561. */
  562.     xxx.z = 0;
  563.     xxx.proto = t->i.protocol;
  564.     xxx.tcplen = intswap(20);
  565.     movebytes(xxx.source,t->i.ipsource,4);
  566.     movebytes(xxx.dest,t->i.ipdest,4);
  567.  
  568.     t->t.check = 0;    
  569.     t->t.check = tcpcheck(&xxx,&t->t,sizeof(struct tcph));
  570. /*
  571. *  IP and data link layers
  572. */    
  573.     movebytes(t->i.ipdest,t->i.ipsource,4);  /* machine it came from */
  574.     movebytes(t->i.ipsource,nnipnum,4); 
  575.     t->i.tlen = intswap(sizeof(IPLAYER)+sizeof(TCPLAYER));
  576.     t->i.ident = nnipident++;
  577.     t->i.ttl = 30;
  578.     t->i.check = 0;
  579.     t->i.check = ipcheck(&t->i,10);
  580.  
  581.     movebytes(t->d.dest,t->d.me,DADDLEN);    /* data link address */
  582.     movebytes(t->d.me,blankd.me,DADDLEN);    /* my address */
  583.  
  584.     return(dlayersend(t,sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(TCPLAYER)));
  585. } /* tcpreset */
  586.  
  587. /************************************************************************
  588. *  tcpinterpret
  589. *  This is called when a packet comes in, passes IP checksumming and is
  590. *  of the TCP protocol type.  Check and see if we are expecting it and
  591. *  where the data should go.
  592. */
  593. int tcpinterpret
  594.   (
  595.     TCPKT *p,
  596.     int tlen
  597.   )
  598.     {
  599.     uint i,myport,hlen,hisport;
  600.     struct port *prt;
  601.     
  602. /*
  603. *  checksum
  604. *    First, fill the pseudo header with its fields, then run our
  605. *  checksum to confirm it.
  606. *
  607. */
  608.     if (p->t.check) {
  609.         movebytes(tcps.source,p->i.ipsource,8);  /* move both addresses */
  610.         tcps.z = 0;
  611.         tcps.proto = p->i.protocol;
  612.  
  613.         tcps.tcplen = intswap(tlen);            /* byte-swapped length */
  614.  
  615.         if (tcpcheck(&tcps,&p->t,tlen)) {    /* compute checksum */
  616.             netposterr(400);
  617.             return(2);
  618.         }
  619.     }
  620.  
  621. /*
  622. *  find the port which is associated with the incoming packet
  623. *  First try open connections, then try listeners
  624. */
  625.     myport = intswap(p->t.dest);
  626.     hisport = intswap(p->t.source);
  627.     hlen = p->t.hlen >> 2;                /* bytes offset to data */
  628.  
  629.  
  630.     for (i=0; i<NPORTS; i++) {
  631.  
  632.         prt = portlist[i];
  633.  
  634.         if (prt != NULL && prt->in.port == myport && prt->out.port == hisport) {
  635.             pnum = i;
  636.             return(tcpdo(prt,p,tlen,hlen));
  637.         }
  638.  
  639.     }
  640.  
  641. /*
  642. *  check to see if the incoming packet should go to a listener
  643. */
  644.  
  645.     for (i=0; i < NPORTS; i++) {
  646.         prt = portlist[i];
  647.  
  648.         if (prt != NULL && !prt->out.port && 
  649.             prt->in.port == myport && (p->t.flags & TSYN)) {
  650.             pnum = i;
  651.             return(tcpdo(prt,p,tlen,hlen));
  652.             }
  653.  
  654.     }
  655.  
  656. /*
  657. *  no matching port was found to handle this packet, reject it
  658. */
  659.  
  660.         tcpreset(p);                /* tell them they are crazy */
  661.         if (!(p->t.flags & TSYN))    /* no error message if it is a SYN */
  662.             netposterr(407);            /* invalid port for incoming packet */
  663.  
  664.         return(1);                    /* no port matches */
  665.  
  666. } /* tcpinterpret */
  667.